package com.assistant.ai;

import com.assistant.core.AssistantEngine;
import com.assistant.core.Config;
import com.assistant.core.CommandData;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author Anyang
 * @version 1.0.0
 * @date 2025/10/25 05:10:08
 * @description 语言理解模块
 */
public class NLUModule {
    private static final Logger logger = LoggerFactory.getLogger(NLUModule.class);
    private final HttpClient httpClient;
    private final Gson gson;
    private final AssistantEngine assistantEngine;
    private final List<JsonObject> conversationHistory;
    private static final int MAX_HISTORY_TURNS = 5;

    public NLUModule(AssistantEngine assistantEngine) {
        this.assistantEngine = assistantEngine;
        this.httpClient = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_2)
                .connectTimeout(Duration.ofSeconds(10))
                .build();
        this.gson = new Gson();
        this.conversationHistory = new ArrayList<>();
    }

    /**
     * 【新增】将消息添加到历史记录，并进行修剪
     */
    private void addMessageToHistory(String role, String content) {
        JsonObject message = new JsonObject();
        message.addProperty("role", role);
        message.addProperty("content", content);
        this.conversationHistory.add(message);

        // 修剪历史，防止 token 溢出
        while (this.conversationHistory.size() > MAX_HISTORY_TURNS * 2) {
            this.conversationHistory.remove(0); // 移除最旧的用户消息
            this.conversationHistory.remove(0); // 移除最旧的助手消息
        }
    }

    /**
     * 【新增】清除对话历史
     */
    public void clearHistory() {
        this.conversationHistory.clear();
        logger.info("对话历史已清除。");
    }

    /**
     * 【修改】parseCommand 现在也使用对话历史（用于上下文指令）
     */
    public CommandData parseCommand(String userQuery) {
        String token = Config.LLM_API_KEY;

        if (token == null || token.isEmpty()) {
            return new CommandData("error", "", "抱歉，NLU 核心配置 Key 未加载，无法理解您的指令。");
        }

        String apiUrl = Config.QIANFAN_CHAT_URL;

        // 【修改】构建带历史记录的消息列表
        JsonArray messages = new JsonArray();
        for (JsonObject msg : this.conversationHistory) {
            messages.add(msg);
        }
        // 添加当前用户输入
        JsonObject userMessage = new JsonObject();
        userMessage.addProperty("role", "user");
        userMessage.addProperty("content", userQuery);
        messages.add(userMessage);
        // 注意：我们不在此时将用户消息加入 *永久* 历史，等待助手响应后再一起加入

        JsonObject jsonBody = new JsonObject();
        jsonBody.addProperty("model", Config.QIANFAN_MODEL_NAME);
        jsonBody.add("messages", messages);
        jsonBody.addProperty("system", Config.SYSTEM_PROMPT);
        jsonBody.addProperty("temperature", 0.01);

        logger.info("【千帆请求】发送指令: {}，使用模型: {}", userQuery, Config.QIANFAN_MODEL_NAME);

        try {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(apiUrl))
                    .header("Content-Type", "application/json")
                    .header("Authorization", "Bearer " + token)
                    .timeout(Duration.ofSeconds(30))
                    .POST(HttpRequest.BodyPublishers.ofString(jsonBody.toString()))
                    .build();

            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() != 200) {
                logger.error("NLU API 调用失败，状态码: {}, 响应体: {}", response.statusCode(), response.body());
                return new CommandData("error", "", String.format("API 调用失败（状态码：%d）。", response.statusCode()));
            }

            JsonObject responseJson = gson.fromJson(response.body(), JsonObject.class);

            if (responseJson.has("error_code")) {
                logger.error("NLU API 业务错误，错误码: {}, 消息: {}",
                        responseJson.get("error_code").getAsInt(),
                        responseJson.get("error_msg").getAsString());
                // 【修改】如果达到 RPM 限制，返回一个特殊的 "error" CommandData
                if (responseJson.get("error_code").getAsInt() == 336501 || responseJson.get("error_code").getAsInt() == 17) {
                    return new CommandData("error_ratelimit", "", responseJson.get("error_msg").getAsString());
                }
                return new CommandData("error", "", String.format("抱歉，模型服务出现错误: %s", responseJson.get("error_msg").getAsString()));
            }

            if (!responseJson.has("result")) {
                return new CommandData("error", "", "模型返回格式异常，缺少 result 字段。");
            }

            String content = responseJson.get("result").getAsString().trim();

            try {
                String jsonString = content.replaceAll("```json|```", "").trim();
                CommandData commandData = gson.fromJson(jsonString, CommandData.class);

                if (commandData.getAction().isEmpty()) {
                    logger.warn("【NLU结果】解析成功，但 Action 字段为空。原始内容: {}", jsonString);
                    return new CommandData("error", "", "模型未能解析出明确的指令意图。");
                }

                logger.info("【NLU结果】解析成功：{}", commandData.toString());

                // 【新增】只有在 NLU 成功解析出 *非问答* 指令时，才将“用户指令”和“指令JSON”加入历史
                // 问答/聊天交由 generateTextStream 自己管理历史
                if (!commandData.getAction().equals("answer_question")) {
                    addMessageToHistory("user", userQuery);
                    // 助手返回的是 JSON 指令
                    addMessageToHistory("assistant", jsonString);
                }

                return commandData;

            } catch (JsonSyntaxException e) {
                logger.warn("【NLU结果】模型返回内容不是有效 JSON，按文本回复处理。内容: {}", content);
                // 【修改】如果返回的不是 JSON，也当作聊天/问答处理
                // 我们构造一个 answer_question 命令，prompt 就是 LLM 的非 JSON 回复
                return new CommandData("answer_question", "", content);
            }

        } catch (IOException | InterruptedException e) {
            logger.error("NLU API 网络请求失败", e);
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            logger.error("NLU 结果解析失败", e);
        }

        return new CommandData("error", "", "抱歉，解析模型返回的指令时发生内部错误。");
    }

    /**
     * 【修改】用于知识问答的流式文本生成（现在支持历史记录）
     */
    public boolean generateTextStream(String prompt, TTSModule ttsModule) {
        String token = Config.LLM_API_KEY;
        if (token == null || token.isEmpty()) {
            logger.error("【文本生成】NLU 核心配置 Key 未加载。");
            return false;
        }

        String apiUrl = Config.QIANFAN_CHAT_URL;

        // 【修改】构建带历史记录的消息列表
        JsonArray messages = new JsonArray();
        for (JsonObject msg : this.conversationHistory) {
            messages.add(msg);
        }
        // 添加当前用户输入
        JsonObject userMessage = new JsonObject();
        userMessage.addProperty("role", "user");
        userMessage.addProperty("content", prompt);
        messages.add(userMessage);

        // 【新增】立即将用户消息加入历史
        addMessageToHistory("user", prompt);


        JsonObject jsonBody = new JsonObject();
        jsonBody.addProperty("model", Config.QIANFAN_MODEL_NAME);
        jsonBody.add("messages", messages);
        jsonBody.addProperty("temperature", 0.7);
        jsonBody.addProperty("stream", true);

        logger.info("【千帆流式请求】发送聊天/问答 Prompt: {}", prompt);

        try {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(apiUrl))
                    .header("Content-Type", "application/json")
                    .header("Authorization", "Bearer " + token)
                    .timeout(Duration.ofSeconds(120))
                    .POST(HttpRequest.BodyPublishers.ofString(jsonBody.toString()))
                    .build();

            HttpResponse<Stream<String>> response = httpClient.send(request, HttpResponse.BodyHandlers.ofLines());

            if (response.statusCode() != 200) {
                logger.error("文本生成 API 调用失败，状态码: {}", response.statusCode());
                // 【新增】如果失败，从历史中移除刚刚添加的用户消息
                this.conversationHistory.remove(this.conversationHistory.size() - 1);
                return false;
            }

            StringBuilder sentenceBuffer = new StringBuilder();
            StringBuilder fullResponseBuffer = new StringBuilder();

            response.body().forEach(line -> {
                if (line.startsWith("data:")) {
                    try {
                        String jsonData = line.substring(5).trim();
                        JsonObject sseData = gson.fromJson(jsonData, JsonObject.class);

                        if (sseData.has("result")) {
                            String delta = sseData.get("result").getAsString();
                            sentenceBuffer.append(delta);
                            fullResponseBuffer.append(delta); // 【新增】收集完整回复

                            String currentText = sentenceBuffer.toString();
                            int sentenceEnd = -1;
                            String[] sentenceEnders = {"。", "！", "？", "\n"};
                            for (String ender : sentenceEnders) {
                                int end = currentText.indexOf(ender);
                                if (end != -1 && (sentenceEnd == -1 || end < sentenceEnd)) {
                                    sentenceEnd = end;
                                }
                            }

                            if (sentenceEnd != -1) {
                                String sentence = currentText.substring(0, sentenceEnd + 1).trim();
                                sentenceBuffer.delete(0, sentenceEnd + 1);

                                if (!sentence.isEmpty()) {
                                    logger.info("【流式播报】: {}", sentence);
                                    ttsModule.speak(sentence);
                                }
                            }
                        }
                    } catch (JsonSyntaxException e) {
                        logger.warn("无法解析 SSE 数据行: {}", line, e);
                    }
                }
            });

            String remainingText = sentenceBuffer.toString().trim();
            if (!remainingText.isEmpty()) {
                logger.info("【流式播报】(末尾): {}", remainingText);
                ttsModule.speak(remainingText);
            }

            // 【新增】将助手的完整回复添加到历史
            String fullAssistantResponse = fullResponseBuffer.toString().trim();
            if (!fullAssistantResponse.isEmpty()) {
                addMessageToHistory("assistant", fullAssistantResponse);
            } else {
                // 如果助手没有回复，也移除刚才的用户消息
                this.conversationHistory.remove(this.conversationHistory.size() - 1);
                logger.warn("【聊天历史】助手回复为空，未添加到历史。");
            }

            return true;

        } catch (IOException | InterruptedException e) {
            logger.error("文本生成 API 网络请求失败", e);
            // 【新增】如果失败，从历史中移除刚刚添加的用户消息
            if (!this.conversationHistory.isEmpty()) {
                this.conversationHistory.remove(this.conversationHistory.size() - 1);
            }
            Thread.currentThread().interrupt();
            return false;
        } finally {
            // 【【【【【 核心修复：重置状态机 】】】】】
            // 无论问答成功、失败还是异常，流式任务结束后，
            // 都必须将主程序状态机重置回 SLEEPING，以准备下一次唤醒。
            logger.info("【状态机】(异步)问答流处理完毕，返回 SLEEPING 状态。");
            assistantEngine.setAssistantState(AssistantEngine.State.SLEEPING);

        }
    }

    /**
     * 【修改】用于文本创作的流式文本生成（现在也使用历史记录）
     * (这允许你执行 "帮我写首诗" -> "太短了，再写长一点" 这样的上下文创作)
     */
    public String generateTextStream(String prompt) {
        String token = Config.LLM_API_KEY;
        if (token == null || token.isEmpty()) {
            logger.error("【文本生成】NLU 核心配置 Key 未加载。");
            return null;
        }

        String apiUrl = Config.QIANFAN_CHAT_URL;

        // 【修改】构建带历史记录的消息列表
        JsonArray messages = new JsonArray();
        for (JsonObject msg : this.conversationHistory) {
            messages.add(msg);
        }
        // 添加当前用户输入
        JsonObject userMessage = new JsonObject();
        userMessage.addProperty("role", "user");
        userMessage.addProperty("content", prompt);
        messages.add(userMessage);

        // 【新增】立即将用户消息加入历史
        addMessageToHistory("user", prompt);

        JsonObject jsonBody = new JsonObject();
        jsonBody.addProperty("model", Config.QIANFAN_MODEL_NAME);
        jsonBody.add("messages", messages);
        jsonBody.addProperty("temperature", 0.7);
        jsonBody.addProperty("system", Config.CHAT_SYSTEM_PROMPT);
        jsonBody.addProperty("stream", true);



        logger.info("【千帆流式请求-文本创作】发送 Prompt: {}", prompt);

        StringBuilder fullResponse = new StringBuilder();

        try {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(apiUrl))
                    .header("Content-Type", "application/json")
                    .header("Authorization", "Bearer " + token)
                    .timeout(Duration.ofSeconds(120))
                    .POST(HttpRequest.BodyPublishers.ofString(jsonBody.toString()))
                    .build();

            HttpResponse<Stream<String>> response = httpClient.send(request, HttpResponse.BodyHandlers.ofLines());

            if (response.statusCode() != 200) {
                logger.error("文本生成 API 调用失败，状态码: {}", response.statusCode());
                // 【新增】如果失败，从历史中移除刚刚添加的用户消息
                this.conversationHistory.remove(this.conversationHistory.size() - 1);
                return null;
            }

            response.body().forEach(line -> {
                if (line.startsWith("data:")) {
                    try {
                        String jsonData = line.substring(5).trim();
                        JsonObject sseData = gson.fromJson(jsonData, JsonObject.class);

                        if (sseData.has("result")) {
                            String delta = sseData.get("result").getAsString();
                            fullResponse.append(delta);
                        }
                    } catch (JsonSyntaxException e) {
                        logger.warn("无法解析 SSE 数据行: {}", line, e);
                    }
                }
            });

            String resultText = fullResponse.toString().trim();
            if (resultText.isEmpty()) {
                logger.warn("【文本生成】流式响应结束，但未收到任何有效文本。");
                // 【新增】如果助手没有回复，也移除刚才的用户消息
                this.conversationHistory.remove(this.conversationHistory.size() - 1);
                return null;
            }

            // 【新增】将助手的完整回复添加到历史
            addMessageToHistory("assistant", resultText);

            logger.info("【文本生成】流式响应聚合完成，总长度: {} 字符。", resultText.length());
            return resultText;

        } catch (IOException | InterruptedException e) {
            logger.error("文本生成 API 网络请求失败", e);
            // 【新增】如果失败，从历史中移除刚刚添加的用户消息
            if (!this.conversationHistory.isEmpty()) {
                this.conversationHistory.remove(this.conversationHistory.size() - 1);
            }
            Thread.currentThread().interrupt();
            return null;
        }
    }
}